maven - 聚合/继承 以及Scope的分类
聚合
简单的方式来编译项目,jar和插件版本统一管理
依赖管理
利用<dependencyManagement>
元素,可被继承。dependencyManagement的特性:在dependencyManagement中配置的元素既不会给parent引入依赖,也不会给它的子模块引入依赖,仅仅是它的配置是可继承的。
parent中定义
<dependencyManagement>
<dependencies>
<dependency>
<groupId>your groupId</groupId>
<artifactId>yourartifactId</artifactId>
<version>${target.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
子项目中添加依赖不需要指定版本
<dependencies>
<dependency>
<groupId>your groupId</groupId>
<artifactId>yourartifactId</artifactId>
</dependency>
</dependencies>
插件管理
利用<pluginManagement>
元素,配置方式同上
注意以下几点:
- 该aggregator本身也做为一个Maven项目,它必须有自己的POM
- 它的打包方式必须为: pom
- 引入了新的元素:modules---module
- 版本:聚合模块的版本和被聚合模块版本一致
-
relative path
:每个module的值都是一个当前POM的相对目录 - 目录名称:为了方便的快速定位内容,模块所处的目录应当与其artifactId一致(Maven约定而不是硬性要求),总之,模块所处的目录必须和<module>模块所处的目录</module>相一致。
- 习惯约定:为了方便构建,通常将聚合模块放在项目目录层的最顶层,其它聚合模块作为子目录存在。这样当我们打开项目的时候,第一个看到的就是聚合模块的POM
- 聚合模块减少的内容:聚合模块的内容仅仅是一个pom.xml文件,它不包含src/main/java、src/test/java等目录,因为它只是用来帮助其它模块构建的工具,本身并没有实质的内容。
- 聚合模块和子模块的目录:他们可以是父子类,也可以是平行结构,当然如果使用平行结构,那么聚合模块的POM也需要做出相应的更改。
继承
做面向对象编程的人都会觉得这是一个没意义的问题,是的,继承就是避免重复,maven的继承也是这样,它还有一个好处就是让项目更加安全
情景分析二:我们在项目开发的过程中,可能多个模块独立开发,但是多个模块可能依赖相同的元素,比如说每个模块都需要Junit,使用spring的时候,其核心jar也必须都被引入,在编译的时候,maven-compiler-plugin插件也要被引入
如何配置继承:
- 到继承肯定是一个父子结构,那么我们在aggregator中来创建一个parent project
-
<packaging>
: 作为父模块的POM,其打包类型也必须为POM - 结构:父模块只是为了帮助我们消除重复,所以它也不需要src/main/java、src/test/java等目录
- 新的元素:
<parent>
, 它是被用在子模块中的 -
<parent>
元素的属性:<relativePath>
: 表示父模块POM的相对路径,在构建的时候,Maven会先根据relativePath检查父POM,如果找不到,再从本地仓库查找 - relativePath的默认值: ../pom.xml
- 子模块省略groupId和version: 使用了继承的子模块中可以不声明groupId和version, 子模块将隐式的继承父模块的这两个元素
可被继承的POM元素
groupId:项目组ID,项目坐标的核心元素
version: 项目版本, 项目坐标的核心元素
description: 项目的描述信息
organization: 项目的组织信息
inceptionYear: 项目的创始年份
url: 项目的URL地址
developers: 项目开发者信息
contributors: 项目的贡献者信息
distributionManagement: 项目的部署配置
issueManagement: 项目的缺陷跟踪系统信息
ciManagement: 项目的持续集成系统信息
scm: 项目的版本控制系统信息
mailingLists: 项目的邮件列表信息
properties: 自定义的maven属性
dependencies: 项目的依赖配置
dependencyManagement: 项目的依赖管理配置
repositories: 项目的仓库配置
build: 包括项目的源码目录配置、输出目录配置、插件配置、插件管理配置等
reporting: 包括项目的报告输出目录配置、报告插件配置等
DependencyManagement应用场景
当我们的项目模块很多的时候,我们使用Maven管理项目非常方便,帮助我们管理构建、文档、报告、依赖、scms、发布、分发的方法。可以方便的编译代码、进行依赖管理、管理二进制库等等。
由于我们的模块很多,所以我们又抽象了一层,抽出一个itoo-base-parent来管理子项目的公共的依赖。为了项目的正确运行,必须让所有的子项目使用依赖项的统一版本,必须确保应用的各个项目的依赖项和版本一致,才能保证测试的和发布的是相同的结果。
在我们项目顶层的POM文件中,我们会看到dependencyManagement元素。通过它元素来管理jar包的版本,让子项目中引用一个依赖而不用显示的列出版本号。Maven会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,然后它就会使用在这个dependencyManagement元素中指定的版本号。
这样做的好处:统一管理项目的版本号,确保应用的各个项目的依赖和版本一致,才能保证测试的和发布的是相同的成果,因此,在顶层pom中定义共同的依赖关系。同时可以避免在每个使用的子项目中都声明一个版本号,这样想升级或者切换到另一个版本时,只需要在父类容器里更新,不需要任何一个子项目的修改;如果某个子项目需要另外一个版本号时,只需要在dependencies中声明一个版本号即可。子类就会使用子类声明的版本号,不继承于父类版本号。
scope的分类
compile
默认就是compile,什么都不配置也就是意味着compile。compile表示被依赖项目需要参与当前项目的编译,当然后续的测试,运行周期也参与其中,是一个比较强的依赖。打包的时候通常需要包含进去。
test
scope为test表示依赖项目仅仅参与测试相关的工作,包括测试代码的编译,执行。比较典型的如junit。
runntime
runntime表示被依赖项目无需参与项目的编译,不过后期的测试和运行周期需要其参与。与compile相比,跳过编译而已,说实话在终端的项目(非开源,企业内部系统)中,和compile区别不是很大。比较常见的如JSR×××的实现,对应的API jar是compile的,具体实现是runtime的,compile只需要知道接口就足够了。oracle jdbc驱动架包就是一个很好的例子,一般scope为runntime。另外runntime的依赖通常和optional搭配使用,optional为true。我可以用A实现,也可以用B实现。
provided
provided意味着打包的时候可以不用包进去,别的设施(Web Container)会提供。事实上该依赖理论上可以参与编译,测试,运行等周期。相当于compile,但是在打包阶段做了exclude的动作。
system
从参与度来说,也provided相同,不过被依赖项不会从maven仓库抓,而是从本地文件系统拿,一定需要配合systemPath属性使用。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。